
import utils from './utils.js';
import { dom, strToNode } from './dom.js'

// loading node
let loadingNode = null;

// alert node
let alertNode = null;

// toast node
let toastNode = null;

let richNode = null;

/**
 * 展示loading或者取消loading
 * 
 * @param {Object} options loading配置，如果传入false，将关闭loading
 * 
 *  入参配置说明：
 * ```js
 * {
 *  theme: {String} 'primary' 主题class，可通过此配置进行个性化样式配置
 *  fade: {Boolean} default false, 是否启用fade进入效果
 *  msg: {String} 提示内容
 * }
 * ```
 * 
 * 使用示例：
 * ```js
 * // 展示简单loading
 * loading();
 * loading(true);
 * 
 * // 展示带提示的loading
 * loading('加载中...');
 * 
 * // 根据配置展示loading
 * loading({theme:'primary', fade:true, msg: '加载中...'});
 * 
 * // 关闭
 * loading(false)
 * 
 * ```
 */
const loading = (options) => {

    // 只有入参是false，才会关闭loading
    if (options === false) {
        // 取消loading
        setBodyFixed(false);
        loadingNode.style.display = 'none';
        return;
    }

    // 如果是字符，设置成msg
    if (utils.isString(options)) options = { msg: options };

    // 未传入配置或者配置不是对象，置成空对象，展示简单的loading效果
    options = !utils.isPlainObject(options) ? {} : options;

    // loading模板
    const loadingTpl = `
        <div class="s-mask"></div>
        <div class="s-modal-center s-loading-block s-grid-x align-center align-middle ${options.theme ? options.theme : ''}">
        <div class="text-center">
            <div class="ani-rotate"></div>
            ${options.msg ? '<div class="s-loading-txt">' + options.msg + '</div>' : ''}
        </div>
        </div>
    `;

    // 如果loadingNode已经创建，直接替换loading内容并展示
    if (loadingNode) {
        loadingNode.innerHTML = loadingTpl;
        loadingNode.style.display = '';
        return;
    }

    // 新增一个loading dom
    const modalTpl = `
    <section id="loading-modal" class="s-modal ${options.fade ? 'ani-fade' : ''}">
    ${loadingTpl}
    </section>
    `

    loadingNode = strToNode(modalTpl);

    // body设置成固定，不可滚动
    setBodyFixed(true);

    dom('body').appendChild(loadingNode);

}

/**
 * 确认弹窗
 * @param {Object} options - 弹窗配置
 * 
 * 配置说明：
 * ```js
 * {
 * msg: {String} 弹窗内容,
 * title: {String} 弹窗标题,
 * fade: {Boolean} 是否启用渐入，默认true
 * confirmText: {String} 确认按钮文案,
 * cancelText: {String} 取消按钮文案,
 * confirmPos: {String} 确认按钮位置，left/right，默认是right
 * theme: {String} 样式主题class，已有主题class dark/success/error/warning
 * }
 * ```
 * 
 * 使用示例：
 * ```js
 * confirm({
 *  title: '标题',
 *  msg: '弹窗内容',
 *  fade: true,
 *  confirmText: '确定继续',
 *  cancelText: '我知道了',
 *  confirmPos: 'left'
 *  theme: 'success'
 * })
 * ```
 */
const confirm = (options) => {

    return new Promise((resolve, reject) => {

        // 校验配置内容
        if (!options || !utils.isPlainObject(options) || !options.msg) {
            return reject(new Error('ConfirmError:the arguments is worng when call function confirm, options is undefined or options is not object or options.msg is undefined'));
        }

        let confirmDom = null;
        let cancelDom = null;
        let btnsNode = null;

        // 按钮node置成null
        let confirmBtnNode = null;
        let cancelBtnNode = null;

        // 先根据按钮配置生成按钮模板
        if (options.confirmText) {
            // 创建确认按钮node，并绑定点击
            confirmBtnNode = strToNode(`<button type="button" class="alert-btn alert-confirm-btn">${options.confirmText}</button>`);
            confirmBtnNode.onclick = () => {
                setBodyFixed(false);
                alertNode.style.display = 'none';
                resolve({ confirm: true });
            }

            confirmDom = document.createElement("div");
            confirmDom.setAttribute('class', 's-cell');
            confirmDom.appendChild(confirmBtnNode);
        }

        if (options.cancelText) {
            // 创建取消按钮node，并绑定点击
            cancelBtnNode = strToNode(`<button type="button" class="alert-btn alert-cancel-btn">${options.cancelText}</button>`);
            cancelBtnNode.onclick = () => {
                setBodyFixed(false);
                alertNode.style.display = 'none';
                resolve({ confirm: false });
            }

            cancelDom = document.createElement("div");
            cancelDom.setAttribute('class', 's-cell');
            cancelDom.appendChild(cancelBtnNode);
        }

        if (confirmDom || cancelDom) {
            btnsNode = document.createElement("div");
            btnsNode.setAttribute("class", "s-grid-x alert-btns")
            if (options.confirmPos && options.confirmPos === 'left' && confirmDom) {
                btnsNode.appendChild(confirmDom);
                cancelDom && btnsNode.appendChild(cancelDom);
            } else {
                cancelDom && btnsNode.appendChild(cancelDom);
                confirmDom && btnsNode.appendChild(confirmDom);
            }
        }

        const alertInnerTpl = `
            <div class="s-mask ${options.transparentMask ? 'opacity_0' : ''}"></div>
            <div class="s-modal-center s-alert-block s-grid-x ${options.theme ? options.theme : ''}">
            <div class="w_100">
                ${options.title ? '<div class="s-alert-title b-b">' + options.title + '</div>' : ''}
                <div class="s-alert-context">${options.msg}</div>
            </div>
            </div>
        `;

        if (alertNode) {
            const classText = `s-modal ${options.fade === false ? '' : 'ani-fade'}`;
            alertNode.className = classText;
            alertNode.innerHTML = alertInnerTpl;
            btnsNode && alertNode.querySelector(".s-alert-context").after(btnsNode);
            alertNode.style.display = '';
            setBodyFixed(true);
            return;
        }

        // 拼装弹窗模板
        const alertTpl = `
            <section id="alert-modal" class="s-modal ${options.fade === false ? '' : 'ani-fade'}">
            ${alertInnerTpl}
            </section>
        `;

        alertNode = strToNode(alertTpl);
        btnsNode && alertNode.querySelector(".s-alert-context").after(btnsNode);

        // body设置成固定，不可滚动
        setBodyFixed(true);

        dom('body').appendChild(alertNode);
    })

}


/**
 * 弹出html内容
 * @param {*} options
 * 
 * options:
 * {
 *  html: String, // html string
 *  closeOnClickMask: Boolean, // 是否开启点击蒙版关闭弹窗
 *  closeOnClicks: String|Array, //需要绑定关闭的dom id,默认是 close
 * }
 *  
 * @returns Promise
 */
const alertHTML = (options) => {

    if (!utils.isString(options) && !utils.isPlainObject(options)) { return Promise.reject(new Error('the argument of alertHTML must be a string or an object')); }

    let opt = {};

    opt = utils.isString(options) ? { html: options } : options;

    richNode = null;

    return new Promise((resolve) => {

        let maskNode = null;
        let htmlNode = null;

        // 创建主节点
        richNode = document.createElement("SECTION");
        richNode.id = "rich-modal";
        richNode.className = "s-modal ani-fade";

        // 创建蒙版节点
        maskNode = document.createElement("DIV");
        maskNode.className = "s-mask";

        if (opt.closeOnClickMask) {
            // 绑定蒙版事件处理，关闭弹窗，并返回false
            maskNode.onclick = () => {
                setBodyFixed(false);
                richNode.style.display = 'none';
                resolve(false);
            }
        }

        // 创建html节点
        htmlNode = strToNode(`
        <div class="s-modal-center s-rich-block">
            ${opt.html}
        </div>
        `);

        if (opt.closeOnClicks) {
            if (utils.isString(opt.closeOnClicks)) {
                bindRichClose(htmlNode, opt.closeOnClicks, resolve)
            } else if (utils.isArray(opt.closeOnClicks)) {
                for (let i = 0; i < opt.closeOnClicks.length; i++) {
                    if (utils.isString(opt.closeOnClicks[i])) {
                        bindRichClose(htmlNode, opt.closeOnClicks[i], resolve)
                    }
                }
            }
        }

        richNode.appendChild(maskNode);
        richNode.appendChild(htmlNode);

        const richModal = dom("#rich-modal");
        if (richModal) {
            richModal.replaceWith(richNode);
            return;
        }

        dom("body").appendChild(richNode);
        setBodyFixed(true);

    })
}

/**
 * 绑定rich弹窗的关闭按钮
 * @param {*} htmlNode 
 * @param {*} selector 
 * @param {*} resolve 
 */
function bindRichClose (htmlNode, selector, resolve) {
    const closeNode = htmlNode.querySelector(selector);
    if (closeNode) {
        closeNode.onclick = () => {
            setBodyFixed(false);
            richNode.style.display = 'none';
            resolve(closeNode.dataset);
        }
    }
}


/**
 * alert风格的弹窗
 * 
 * @param {Object} options
 * 
 * 配置说明：
 * ```js
 * {
 *  msg: {String} 弹窗内容
 *  btnText: {String} 按钮文案
 *  btnType: {String} 按钮类型，confirm/cancel， confirm-按钮会以confirm按钮样式展示，cancel-按钮会以cancel按钮样式展示，参考confirm api
 * }
 * ````  
 * 
 * 使用示例：
 * ```js
 * // 简单的弹窗
 * alert('测试alert弹窗')
 * 
 * // 配置按钮文案的弹窗
 * alert({msg:'配置按钮的弹窗', btnText:'我知道了', btnType:'confirm'})
 * ```
 * 
 */
const alert = (options) => {

    if (utils.isPlainObject(options) && !options.msg) return;

    if (!utils.isPlainObject(options)) {
        options = { msg: options };
    }

    options.btnText = options.btnText || '确定';
    options.btnType = options.btnType || 'cancel';

    options.btnType === 'confirm' ? (options.confirmText = options.btnText) : (options.cancelText = options.btnText)

    return confirm(options);

}

// toast关闭定时器
let toastTimer = null;

/**
 * 
 * toast提示
 * 
 * @param {String} msg toast内容
 * @param {Number} delay 大于0的延时关闭时间，单位秒， 
 * @returns 
 */
const toast = (msg, delay = 3) => {

    if (!msg) return;

    // 延时处理
    delay = utils.isNumber(delay) && delay > 0 ? delay * 1000 : 3000;

    const nToastHtml = `
        <div class="s-modal-center s-toast-block s-grid-x">
        <div class="w_100">
            ${msg}
        </div>
        </div>
    `;

    if (toastNode) {
        toastNode.innerHTML = nToastHtml;
        toastNode.style.display = '';
        closeToast(delay);
        return;
    }

    toastNode = strToNode(`
    <section id="toast-modal" class="s-modal ani-fade">
        ${nToastHtml}
    </section>
    `);

    dom('body').appendChild(toastNode);

    closeToast(delay);

}

function closeToast(delay) {

    clearTimeout(toastTimer);

    // 设置定时关闭
    toastTimer = setTimeout(() => {
        setBodyFixed(false);
        toastNode.style.display = 'none';
    }, delay)
}

/**
 * 设置body固定布局，禁止滚动
 * 
 * 用于需要展示弹窗/loading等fixed组件时，需要同时禁止页面滚动的场景
 * 
 * @param {Boolean} fixed 
 */
const setBodyFixed = (fixed) => {
    if (fixed) {
        document.body.style.overflow = 'hidden';
    } else {
        document.body.style.overflow = '';
    }
}

const interact = {
    alert,
    loading,
    confirm,
    toast,
    alertHTML,
    setBodyFixed
}

export default interact;